// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ------------------------------------------------------------------
// Modification history:
// feature: listener code decoupling
// feature: support e2e deadline and liveliness: 1. xml support e2e_deadline and e2e_liveliness config 2. data writer and data reader support e2e deadline and e2e liveliness qos
// feature: change E2E packet format
// feature: agent for vbs
// feature: Add xcdrv2, mutable, optional, id, and their test cases
// feature: the default memory policy change from PREALLOCATED_MEMORY_MODE to PREALLOCATED_WITH_REALLOC_MEMORY_MODE
// feature: destination order support by reception timestamp
// feature: E2E Profile04 and Configuration Function Development
// feature: flowcontroller xml config and writer/reader-resourcelimit
// ------------------------------------------------------------------

#ifndef XMLPARSER_QOSPOLICIES_HPP_
#define XMLPARSER_QOSPOLICIES_HPP_

#include <bitset>
#include <vector>
#include <ostream>
#include <utility>
#include <map>
#include <string>

#include <deps/common/Time_t.h>
#include <deps/common/Types.h>
#include <deps/common/ParameterTypes.hpp>
#include <deps/common/SerializedPayload.h>
#include <deps/common/GuidPrefix_t.hpp>
#include <deps/qos/BaseQosPolicy.hpp>
#include <xmlparser/attributes/XMLRTPSParticipantAttributes.h>
#include <deps/common/PropertyPolicy.h>

#include <xmlparser/XMLParserCommonPart.h>

namespace vbsutil {
namespace xmlparser {

enum IpcMode : uint8_t {
    DEFAULT_IPC = 0,
    DISABLE_INTRA_PROCESS = 1,  // 禁止进程内通信
    DISABLE_INTRA_HOST = 2,     // 禁止进程间通信
    DISABLE_INTER_HOST = 4,     // 禁止域间通信
};

/**
 * Class DeadlineQosPolicy, to indicate the Deadline of the samples.
 * This QosPolicy can be defined and is transmitted to the rest of the network but is not implemented in this version.
 * period: Default value c_TimeInifinite.
 */
class DeadlineQosPolicy : public Parameter_t, public QosPolicy {
 public:
    /**
     * @brief Constructor
     */
    RTPS_DllAPI DeadlineQosPolicy()
        : Parameter_t(PID_DEADLINE, PARAMETER_TIME_LENGTH),
          QosPolicy(),
          period(TIME_T_INFINITE_SECONDS, TIME_T_INFINITE_NANOSECONDS) {}

    /**
     * @brief Destructor
     */
    virtual RTPS_DllAPI ~DeadlineQosPolicy() = default;

    bool operator==(const DeadlineQosPolicy& b) const {
        return (this->period == b.period) && (this->counter == b.counter) &&
               (this->using_e2e_config == b.using_e2e_config) && Parameter_t::operator==(b) && QosPolicy::operator==(b);
    }

    inline void clear() override {
        DeadlineQosPolicy reset = DeadlineQosPolicy();
        std::swap(*this, reset);
    }

 public:
    /**
     * @brief Maximum time expected between samples.
     * It is inconsistent for a DataReader to have a DEADLINE period less than its
     * TimeBasedFilterQosPolicy minimum_separation. <br> By default, c_TimeInifinite.
     */
    Duration_t period;
    uint32_t counter = 5;  //default is 5
    bool using_e2e_config = false;
};

class LivelinessQosPolicy : public Parameter_t, public QosPolicy {
 public:
    /**
     * @brief Constructor
     */
    RTPS_DllAPI LivelinessQosPolicy()
        : Parameter_t(PID_LIVELINESS, PARAMETER_KIND_LENGTH + PARAMETER_TIME_LENGTH),
          QosPolicy(),
          kind(AUTOMATIC_LIVELINESS_QOS),
          lease_duration(TIME_T_INFINITE_SECONDS, TIME_T_INFINITE_NANOSECONDS),
          announcement_period(TIME_T_INFINITE_SECONDS, TIME_T_INFINITE_NANOSECONDS) {}

    /**
     * @brief Destructor
     */
    virtual RTPS_DllAPI ~LivelinessQosPolicy() = default;

    bool operator==(const LivelinessQosPolicy& b) const {
        return (this->kind == b.kind) && (this->lease_duration == b.lease_duration) &&
               (this->announcement_period == b.announcement_period) && Parameter_t::operator==(b) &&
               QosPolicy::operator==(b);
    }

    inline void clear() override {
        LivelinessQosPolicy reset = LivelinessQosPolicy();
        std::swap(*this, reset);
    }

 public:
    //! Liveliness kind <br> By default, AUTOMATIC_LIVELINESS.
    LivelinessQosPolicyKind kind;
    /*! Period within which liveliness should be asserted.
     *  On a DataWriter it represents the period it commits to signal its liveliness.
     *  On a DataReader it represents the period without assertion after which a DataWriter is
     * considered inactive. By default, c_TimeInfinite.
     */
    Duration_t lease_duration;
    /*! The period for automatic assertion of liveliness.
     *  Only used for DataWriters with AUTOMATIC liveliness.
     *  By default, c_TimeInfinite.
     *
     * @warning When not infinite, must be < lease_duration, and it is advisable to be less than
     * 0.7*lease_duration.
     */
    Duration_t announcement_period;

    bool using_e2e_config = false;
};

class HistoryQosPolicy : public Parameter_t, public QosPolicy {
 public:
    /**
     * @brief Constructor
     */
    RTPS_DllAPI HistoryQosPolicy()
        : Parameter_t(PID_HISTORY, PARAMETER_KIND_LENGTH + 4U), QosPolicy(), kind(KEEP_LAST_HISTORY_QOS), depth(1) {}

    /**
     * @brief Destructor
     */
    virtual RTPS_DllAPI ~HistoryQosPolicy() = default;

    bool operator==(const HistoryQosPolicy& b) const {
        return (this->kind == b.kind) && (this->depth == b.depth) && (Parameter_t::operator==(b)) &&
               (QosPolicy::operator==(b));
    }

    inline void clear() override {
        HistoryQosPolicy reset = HistoryQosPolicy();
        std::swap(*this, reset);
    }

 public:
    //! HistoryQosPolicyKind. <br> By default, KEEP_LAST_HISTORY_QOS.
    HistoryQosPolicyKind kind;
    /*! History depth. <br> By default, 1. If a value other than 1 is specified, it should
     *  be consistent with the settings of the ResourceLimitsQosPolicy.
     *
     *  @warning Only takes effect if the kind is KEEP_LAST_HISTORY_QOS.
     */
    int32_t depth;
};

class ResourceLimitsQosPolicy : public Parameter_t, public QosPolicy {
 public:
    /**
     * @brief Specifies the maximum number of data-samples the DataWriter (or DataReader) can manage
     * across all the instances associated with it. Represents the maximum samples the middleware
     * can store for any one DataWriter (or DataReader). <br> By default, 5000.
     *
     * @warning It is inconsistent if `max_samples < (max_instances * max_samples_per_instance)`.
     */
    int32_t max_samples;
    /**
     * @brief Represents the maximum number of instances DataWriter (or DataReader) can manage. <br>
     * By default, 10.
     *
     * @warning It is inconsistent if `(max_instances * max_samples_per_instance) > max_samples`.
     */
    int32_t max_instances;
    /**
     * @brief Represents the maximum number of samples of any one instance a DataWriter(or
     * DataReader) can manage. <br> By default, 400.
     *
     * @warning It is inconsistent if `(max_instances * max_samples_per_instance) > max_samples`.
     */
    int32_t max_samples_per_instance;
    /**
     * @brief Number of samples currently allocated. <br>
     * By default, 10.
     */
    int32_t allocated_samples;
    /**
     * @brief Represents the extra number of samples available once the max_samples have been
     * reached in the history. This makes it possible, for example, to loan samples even with a full
     * history. By default, 1.
     */
    int32_t extra_samples;

    /**
     * @brief Constructor
     */
    RTPS_DllAPI ResourceLimitsQosPolicy()
        : Parameter_t(PID_RESOURCE_LIMITS, 4U + 4U + 4U),
          QosPolicy(),
          max_samples(5000),
          max_instances(10),
          max_samples_per_instance(400),
          allocated_samples(10),
          extra_samples(1) {}

    /**
     * @brief Destructor
     */
    virtual RTPS_DllAPI ~ResourceLimitsQosPolicy() = default;

    bool operator==(const ResourceLimitsQosPolicy& b) const {
        return (this->max_samples == b.max_samples) && (this->max_instances == b.max_instances) &&
               (this->max_samples_per_instance == b.max_samples_per_instance) &&
               (this->allocated_samples == b.allocated_samples) && (Parameter_t::operator==(b)) &&
               (QosPolicy::operator==(b));
    }

    inline void clear() override {
        ResourceLimitsQosPolicy reset = ResourceLimitsQosPolicy();
        std::swap(*this, reset);
    }
};

/**
 * Specifies the maximum duration of validity of the data written by the DataWriter.
 *
 * @note Mutable Qos Policy
 */
class LifespanQosPolicy : public Parameter_t, public QosPolicy {
 public:
    /**
     * @brief Constructor
     */
    RTPS_DllAPI LifespanQosPolicy()
        : Parameter_t(PID_LIFESPAN, PARAMETER_TIME_LENGTH),
          QosPolicy(),
          duration(TIME_T_INFINITE_SECONDS, TIME_T_INFINITE_NANOSECONDS) {}

    /**
     * @brief Destructor
     */
    virtual RTPS_DllAPI ~LifespanQosPolicy() = default;

    bool operator==(const LifespanQosPolicy& b) const {
        return (this->duration == b.duration) && (Parameter_t::operator==(b)) && (QosPolicy::operator==(b));
    }

    inline void clear() override {
        LifespanQosPolicy reset = LifespanQosPolicy();
        std::swap(*this, reset);
    }

 public:
    //! Period of validity. <br> By default, c_TimeInfinite.
    Duration_t duration;
};

/**
 * Class OwnershipQosPolicy, to indicate the ownership kind of the endpoints.
 * kind: Default value SHARED_OWNERSHIP_QOS.
 */
class OwnershipQosPolicy : public Parameter_t, public QosPolicy {
 public:
    /**
     * @brief Constructor
     */
    RTPS_DllAPI OwnershipQosPolicy()
        : Parameter_t(PID_OWNERSHIP, PARAMETER_KIND_LENGTH), QosPolicy(), kind(SHARED_OWNERSHIP_QOS) {}

    /**
     * @brief Destructor
     */
    virtual RTPS_DllAPI ~OwnershipQosPolicy() = default;

    bool operator==(const OwnershipQosPolicy& b) const {
        return (this->kind == b.kind) && Parameter_t::operator==(b) && QosPolicy::operator==(b);
    }

    inline void clear() override {
        OwnershipQosPolicy reset = OwnershipQosPolicy();
        std::swap(*this, reset);
    }

 public:
    //! OwnershipQosPolicyKind
    OwnershipQosPolicyKind kind;
};

class Partition_t {
    friend class PartitionQosPolicy;

 private:
    const char* partition_;

 private:
    Partition_t() { partition_ = nullptr; }

 public:
    /**
     * @brief Constructor using a pointer
     *
     * @param ptr Pointer to be set
     */
    explicit Partition_t(const void* ptr) { partition_ = (char*)ptr; }

    bool operator==(const Partition_t& rhs) const {
        return ((size() == rhs.size()) && ((size() == 0U) || strcmp(partition_ + 4, rhs.partition_ + 4)));
    }

    bool operator!=(const Partition_t& rhs) const { return !(*this == rhs); }

    /**
     * @brief Getter for the size
     *
     * @return uint32_t with the size
     */
    uint32_t size() const { return *(uint32_t*)partition_; }

    /**
     * @brief Getter for the partition name
     *
     * @return name
     */
    const char* name() const { return partition_ + 4; }
};

class PartitionQosPolicy : public Parameter_t, public QosPolicy {
 public:
    class const_iterator {
     public:
        typedef const_iterator self_type;
        typedef const Partition_t value_type;
        typedef const Partition_t reference;
        typedef const Partition_t* pointer;
        typedef size_t difference_type;
        typedef std::forward_iterator_tag iterator_category;

        /**
         * @brief Constructor using a pointer
         *
         * @param ptr Pointer to be set
         */
        const_iterator(const xmlparser::octet* ptr) : ptr_(ptr), value_(ptr_) {}

        self_type operator++() {
            self_type tmp = *this;
            advance();
            return tmp;
        }

        self_type operator++(int) {
            advance();
            return *this;
        }

        reference operator*() { return value_; }

        pointer operator->() { return &value_; }

        bool operator==(const self_type& rhs) const { return ptr_ == rhs.ptr_; }

        bool operator!=(const self_type& rhs) const { return ptr_ != rhs.ptr_; }

     protected:
        /**
         * @brief Shift the pointer to the next element
         */
        void advance() {
            // Size of the element (with alignment)
            uint32_t size = *(uint32_t*)ptr_;
            ptr_ += (4U + ((size + 3U) & ~3U));
            value_ = Partition_t(ptr_);
        }

     private:
        //! Pointer
        const xmlparser::octet* ptr_;
        //! Partition
        Partition_t value_;
    };

 public:
    /**
     * @brief Constructor without parameters
     */
    RTPS_DllAPI PartitionQosPolicy() : Parameter_t(PID_PARTITION, 0U), QosPolicy(), max_size_(0U), Npartitions_(0U) {}

    /**
     * @brief Constructor using Parameter length
     *
     * @param in_length Length of the parameter
     */
    RTPS_DllAPI PartitionQosPolicy(uint16_t in_length)
        : Parameter_t(PID_PARTITION, in_length),
          QosPolicy(),
          max_size_(in_length),
          partitions_(in_length),
          Npartitions_(0U) {}

    /**
     * @brief Copy constructor
     *
     * @param b Another PartitionQosPolicy instance
     */
    RTPS_DllAPI PartitionQosPolicy(const PartitionQosPolicy& b)
        : Parameter_t(b),
          QosPolicy(b),
          max_size_(b.max_size_),
          partitions_((b.max_size_ != 0U) ? b.partitions_.max_size : b.partitions_.length),
          Npartitions_(b.Npartitions_) {
        (void)partitions_.copy(&b.partitions_, (b.max_size_ != 0U));
    }

    /**
     * @brief Destructor
     */
    virtual RTPS_DllAPI ~PartitionQosPolicy() = default;

    bool operator==(const PartitionQosPolicy& b) const {
        return (this->max_size_ == b.max_size_) && (this->Npartitions_ == b.Npartitions_) &&
               (this->partitions_ == b.partitions_) && (Parameter_t::operator==(b)) && (QosPolicy::operator==(b));
    }

    PartitionQosPolicy& operator=(const PartitionQosPolicy& b) {
        if (this != &b) {
            QosPolicy::operator=(b);
            Parameter_t::operator=(b);
            max_size_ = b.max_size_;
            partitions_.reserve(max_size_ != 0U ? b.partitions_.max_size : b.partitions_.length);
            try {
                (void)partitions_.copy(&b.partitions_, b.max_size_ != 0U);
            } catch (std::bad_alloc&) {
                throw;
            }
            Npartitions_ = b.Npartitions_;
        }

        return *this;
    }

    /**
     * @brief Getter for the first position of the partition list
     *
     * @return const_iterator
     */
    const_iterator begin() const { return const_iterator(partitions_.data); }

    /**
     * @brief Getter for the end of the partition list
     *
     * @return const_iterator
     */
    const_iterator end() const { return const_iterator(partitions_.data + partitions_.length); }

    /**
     * @brief Getter for the number of partitions
     *
     * @return uint32_t with the size
     */
    uint32_t size() const { return Npartitions_; }

    /**
     * @brief Check if the set is empty
     *
     * @return true if it is empty, false otherwise
     */
    uint32_t empty() const { return (Npartitions_ == 0U); }

    /**
     * @brief Setter for the maximum size reserved for partitions (in bytes)
     *
     * @param size Size to be set
     */
    void set_max_size(uint32_t size) {
        partitions_.reserve(size);
        max_size_ = size;
    }

    /**
     * @brief Getter for the maximum size (in bytes)
     *
     * @return uint32_t with the maximum size
     */
    uint32_t max_size() const { return max_size_; }

    /**
     * Appends a name to the list of partition names.
     *
     * @param name Name to append.
     */
    RTPS_DllAPI inline void push_back(const char* name) {
        // Realloc if needed;
        uint32_t size = (uint32_t)strlen(name) + 1U;
        uint32_t alignment = ((size + 3U) & ~3U) - size;

        if ((max_size_ != 0U) && (partitions_.max_size < partitions_.length + size + alignment + 4U)) {
            return;
        }

        partitions_.reserve(partitions_.length + size + alignment + 4U);

        xmlparser::octet* o = (xmlparser::octet*)&size;
        (void)memcpy(partitions_.data + partitions_.length, o, 4U);
        partitions_.length += 4U;

        (void)memcpy(partitions_.data + partitions_.length, name, size);
        partitions_.length += size;

        (void)memset(partitions_.data + partitions_.length, 0, alignment);
        partitions_.length += alignment;

        ++Npartitions_;
        hasChanged = true;
    }

    /**
     * Clears list of partition names
     */
    RTPS_DllAPI inline void clear() override {
        partitions_.length = 0U;
        Npartitions_ = 0U;
        hasChanged = false;
    }

    /**
     * Returns partition names.
     *
     * @return Vector of partition name strings.
     */
    RTPS_DllAPI inline const std::vector<std::string> getNames() const { return names(); }

    /**
     * Overrides partition names
     *
     * @param nam Vector of partition name strings.
     */
    RTPS_DllAPI inline void setNames(std::vector<std::string>& nam) { names(nam); }

    /**
     * Returns partition names.
     *
     * @return Vector of partition name strings.
     */
    RTPS_DllAPI inline const std::vector<std::string> names() const {
        std::vector<std::string> names;
        if (Npartitions_ > 0U) {
            for (auto it = begin(); it != end(); ++it) {
                names.push_back(it->name());
            }
        }
        return names;
    }

    /**
     * Overrides partition names
     *
     * @param nam Vector of partition name strings.
     */
    RTPS_DllAPI inline void names(std::vector<std::string>& nam) {
        clear();
        for (auto it = nam.begin(); it != nam.end(); ++it) {
            push_back(it->c_str());
        }
        hasChanged = true;
    }

 private:
    //! Maximum size <br> By default, 0.
    uint32_t max_size_;
    //! Partitions
    xmlparser::SerializedPayload_t partitions_;
    //! Number of partitions. <br> By default, 0.
    uint32_t Npartitions_;
};

/**
 * Class DisablePositiveACKsQosPolicy to disable sending of positive ACKs
 *
 * @note Immutable Qos Policy
 */
class DisablePositiveACKsQosPolicy : public Parameter_t, public QosPolicy {
 public:
    /**
     * @brief Constructor
     */
    RTPS_DllAPI DisablePositiveACKsQosPolicy()
        : Parameter_t(PID_DISABLE_POSITIVE_ACKS, PARAMETER_BOOL_LENGTH),
          QosPolicy(),
          enabled(false),
          duration(TIME_T_INFINITE_SECONDS, TIME_T_INFINITE_NANOSECONDS) {}

    /**
     * @brief Destructor
     */
    virtual RTPS_DllAPI ~DisablePositiveACKsQosPolicy() = default;

    bool operator==(const DisablePositiveACKsQosPolicy& b) const {
        return (enabled == b.enabled) && (Parameter_t::operator==(b)) && (QosPolicy::operator==(b));
    }

    inline void clear() override {
        DisablePositiveACKsQosPolicy reset = DisablePositiveACKsQosPolicy();
        std::swap(*this, reset);
    }

 public:
    //! True if this QoS is enabled. <br> By default, false
    bool enabled;
    //! The duration to keep samples for (not serialized as not needed by reader). <br> By default,
    //! c_TimeInfinite
    Duration_t duration;
};

class OwnershipStrengthQosPolicy : public Parameter_t, public QosPolicy {
 public:
    /**
     * @brief Constructor
     */
    RTPS_DllAPI OwnershipStrengthQosPolicy() : Parameter_t(PID_OWNERSHIP_STRENGTH, 4U), QosPolicy(), value(0U) {}

    /**
     * @brief Destructor
     */
    virtual RTPS_DllAPI ~OwnershipStrengthQosPolicy() = default;

    bool operator==(const OwnershipStrengthQosPolicy& b) const {
        return (this->value == b.value) && (Parameter_t::operator==(b)) && (QosPolicy::operator==(b));
    }

    inline void clear() override {
        OwnershipStrengthQosPolicy reset = OwnershipStrengthQosPolicy();
        std::swap(*this, reset);
    }

 public:
    //! Strength <br> By default, 0.
    uint32_t value;
};
#if 0
class BatchQosPolicy : public QosPolicy {
public:
    /**
     * @brief Constructor
     */
    RTPS_DllAPI BatchQosPolicy()
        : QosPolicy()
        , enable(false)
        , max_data_bytes(4096)
        , max_samples(LENGTH_UNLIMITED)
        , max_flush_delay(TIME_T_INFINITE_SECONDS, TIME_T_INFINITE_NANOSECONDS) {}

    /**
     * @brief Destructor
     */
    virtual RTPS_DllAPI ~BatchQosPolicy() = default;

    bool operator==(const BatchQosPolicy& b) const {
        return (this->enable == b.enable) && (this->max_data_bytes == b.max_data_bytes) &&
            (this->max_samples == b.max_samples) && (this->max_flush_delay == b.max_flush_delay);
    }

    inline void clear() override {
        BatchQosPolicy reset = BatchQosPolicy();
        std::swap(*this, reset);
    }

public:
    bool enable;
    uint32_t max_data_bytes;
    uint32_t max_samples;
    /**
     * @brief The maximum flush delay. A batch is flushed automatically after the
     * delay specified by this parameter. As its value is DURATION_INFINITE,
     * the flush event will be triggered by max_data_bytes.
     */
    Duration_t max_flush_delay;
};
#endif

/**
 * Enum PublishModeQosPolicyKind, different kinds of publication synchronism
 */
typedef enum PublishModeQosPolicyKind : xmlparser::octet {
    SYNCHRONOUS_PUBLISH_MODE,  //!< Synchronous publication mode (default for writers).
    ASYNCHRONOUS_PUBLISH_MODE  //!< Asynchronous publication mode.
} PublishModeQosPolicyKind_t;

/**
 * Class PublishModeQosPolicy, defines the publication mode for a specific writer.
 */
class PublishModeQosPolicy : public QosPolicy {
 public:
    //! PublishModeQosPolicyKind <br> By default, SYNCHRONOUS_PUBLISH_MODE.
    PublishModeQosPolicyKind kind = SYNCHRONOUS_PUBLISH_MODE;

    /*! Name of the flow controller used when publish mode kind is ASYNCHRONOUS_PUBLISH_MODE.
     *
     * @since 2.4.0
     */
    const char* flow_controller_name = flowctlString::EDDS_FLOW_CONTROLLER_DEFAULT;

    inline void clear() override {
        PublishModeQosPolicy reset = PublishModeQosPolicy();
        std::swap(*this, reset);
    }

    bool operator==(const PublishModeQosPolicy& b) const {
        return (this->kind == b.kind) && (0 == strcmp(flow_controller_name, b.flow_controller_name)) &&
               (QosPolicy::operator==(b));
    }

    std::string flowname;
};

/**
 * Class E2EProtection to enable e2e protection
 *
 * @note Immutable Qos Policy
 */
class E2EProtectionQosPolicy : public Parameter_t, public QosPolicy {
 public:
    /**
     * @brief Constructor
     */
    RTPS_DllAPI E2EProtectionQosPolicy()
        : Parameter_t(PID_E2E_PROTECTION, PARAMETER_BOOL_LENGTH),
          QosPolicy(),
          enabled(false),
          needCheckEnableFlag(false),
          MinDataLength(0U),
          MaxDataLength(0U),
          MaxDeltaCounter(0U) {}

    /**
     * @brief Destructor
     */
    virtual RTPS_DllAPI ~E2EProtectionQosPolicy() = default;

    bool operator==(const E2EProtectionQosPolicy& b) const {
        return (enabled == b.enabled) && (Parameter_t::operator==(b)) && (QosPolicy::operator==(b));
    }

    inline void clear() override {
        E2EProtectionQosPolicy reset = E2EProtectionQosPolicy();
        std::swap(*this, reset);
    }

 public:
    //! True if this QoS is enabled. <br> By default, false
    bool enabled;
    bool needCheckEnableFlag;
    uint16_t MinDataLength;
    uint16_t MaxDataLength;
    uint16_t MaxDeltaCounter;
};

//! Holds allocation limits affecting collections managed by a participant.
//using ParticipantResourceLimitsQos = xmlparser::RTPSParticipantAllocationAttributes;

//! Property policies
// using PropertyPolicyQos = xmlparser::PropertyPolicy;

//! Qos Policy that configures the wire protocol
class WireProtocolConfigQos : public QosPolicy {
 public:
    /**
     * @brief Constructor
     */
    RTPS_DllAPI WireProtocolConfigQos() : QosPolicy(), participant_id(-1) {}

    /**
     * @brief Destructor
     */
    virtual RTPS_DllAPI ~WireProtocolConfigQos() = default;

    bool operator==(const WireProtocolConfigQos& b) const {
        return (this->prefix == b.prefix) && (this->participant_id == b.participant_id) &&
               (this->builtin == b.builtin) && (this->port == b.port) &&
               (this->default_unicast_locator_list == b.default_unicast_locator_list) &&
               (this->default_multicast_locator_list == b.default_multicast_locator_list) &&
               (this->default_external_unicast_locators == b.default_external_unicast_locators) &&
               (this->ignore_non_matching_locators == b.ignore_non_matching_locators) && (QosPolicy::operator==(b));
    }

    inline void clear() override {
        WireProtocolConfigQos reset = WireProtocolConfigQos();
        std::swap(*this, reset);
    }

    //! Optionally allows user to define the GuidPrefix_t
    xmlparser::GuidPrefix_t prefix;

    //! Participant ID <br> By default, -1.
    int32_t participant_id;

    //! Builtin parameters.
    xmlparser::BuiltinAttributes builtin;

    //! Port Parameters
    xmlparser::PortParameters port;

    /**
     * Default list of Unicast Locators to be used for any Endpoint defined inside this
     * RTPSParticipant in the case that it was defined with NO UnicastLocators. At least ONE locator
     * should be included in this list.
     */
    xmlparser::LocatorList default_unicast_locator_list;

    /**
     * Default list of Multicast Locators to be used for any Endpoint defined inside this
     * RTPSParticipant in the case that it was defined with NO MulticastLocators. This is usually
     * left empty.
     */
    xmlparser::LocatorList default_multicast_locator_list;

    /**
     * The collection of external locators to use for communication on user created topics.
     */
    xmlparser::ExternalLocators default_external_unicast_locators;

    /**
     * Whether locators that don't match with the announced locators should be kept.
     */
    bool ignore_non_matching_locators = false;
};

//! Qos Policy to configure the limit of the writer resources
class WriterResourceLimitsQos {
 public:
    /**
     * @brief Constructor
     */
    RTPS_DllAPI WriterResourceLimitsQos() : matched_subscriber_allocation(), reader_filters_allocation(0U, 32U, 1U) {}

    /**
     * @brief Destructor
     */
    virtual RTPS_DllAPI ~WriterResourceLimitsQos() = default;

    bool operator==(const WriterResourceLimitsQos& b) const {
        return (matched_subscriber_allocation == b.matched_subscriber_allocation) &&
               (reader_filters_allocation == b.reader_filters_allocation);
    }

    //! Matched subscribers allocation limits.
    xmlparser::ResourceLimitedContainerConfig matched_subscriber_allocation;
    //! Reader filters allocation limits.
    xmlparser::ResourceLimitedContainerConfig reader_filters_allocation;
};

/**
 * Enum DestinationOrderQosPolicyKind, different kinds of destination order for DestinationOrderQosPolicy.
 */
enum DestinationOrderQosPolicyKind : xmlparser::octet {
    /**
     * Indicates that data is ordered based on the reception time at each Subscriber. Since each subscriber may receive
     * the data at different times there is no guaranteed that the changes will be seen in the same order. Consequently,
     * it is possible for each subscriber to end up with a different final value for the data.
     */
    BY_RECEPTION_TIMESTAMP_DESTINATIONORDER_QOS,
    /**
     * Indicates that data is ordered based on a timestamp placed at the source (by the Service or by the application).
     * In any case this guarantees a consistent final value for the data in all subscribers.
     */
    BY_SOURCE_TIMESTAMP_DESTINATIONORDER_QOS
};

/**
 * Controls the criteria used to determine the logical order among changes made by Publisher entities to the same instance of
 * data (i.e., matching Topic and key).
 *
 * @warning This QosPolicy can be defined and is transmitted to the rest of the network but is not implemented in this version.
 *
 * @note Immutable Qos Policy
 */
class DestinationOrderQosPolicy : public Parameter_t, public QosPolicy {
 public:
    /**
     * @brief Constructor
     */
    RTPS_DllAPI DestinationOrderQosPolicy()
        : Parameter_t(PID_DESTINATION_ORDER, PARAMETER_KIND_LENGTH),
          QosPolicy(),
          kind(BY_RECEPTION_TIMESTAMP_DESTINATIONORDER_QOS) {}

    /**
     * @brief Destructor
     */
    virtual RTPS_DllAPI ~DestinationOrderQosPolicy() = default;

    bool operator==(const DestinationOrderQosPolicy& b) const {
        return (this->kind == b.kind) && Parameter_t::operator==(b) && QosPolicy::operator==(b);
    }

    inline void clear() override {
        DestinationOrderQosPolicy reset = DestinationOrderQosPolicy();
        std::swap(*this, reset);
    }

 public:
    //!DestinationOrderQosPolicyKind. <br> By default, BY_RECEPTION_TIMESTAMP_DESTINATIONORDER_QOS.
    DestinationOrderQosPolicyKind kind;
};

// dsf related config
enum QueueWakeUp : uint32_t { PTHREAD_CONDITION_WAKE_UP, DTS_WAKE_UP, INVALID_WAKE_UP };

inline QueueWakeUp StrToQueueWakeUp(const std::string& str) {
    std::map<std::string, QueueWakeUp> strToEnum = {{"PTHREAD_CONDITION_WAKE_UP", PTHREAD_CONDITION_WAKE_UP},
                                                    {"DTS_WAKE_UP", DTS_WAKE_UP},
                                                    {"INVALID_WAKE_UP", INVALID_WAKE_UP}};
    auto itr = strToEnum.find(str);
    if (itr != strToEnum.end()) {
        return itr->second;
    }
    return INVALID_WAKE_UP;
}

}  // namespace xmlparser
}  // namespace vbsutil

#endif  // INCLUDE_EDDS_DDS_CORE_POLICY_QOSPOLICIES_HPP_
